﻿<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

	<head>
		<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
		<title>ASP.NET Boilerplate - Module Zero</title>
		<link type="text/css" rel="stylesheet" href="../bootstrap.min.css" />
	</head>

	<body>

		<div class="document-contents">

			<h3>Introduction</h3>

			<p>ASP.NET Boilerplate defines a strong UI
				<a href="/Pages/Documents/Localization">localization system</a> which is 
	used both in server and client side. It allows to easily configure 
	application languages and define localization texts (strings) in different 
	sources (Resource files and XML files are two pre-defined source).</p>
			<p>While it's good for most cases, we may want to define languages and texts
				<strong>dynamically </strong>on a <strong>database</strong>. Module-Zero 
	allows us to dynamically manage application <strong>languages</strong> and
				<strong>texts</strong>
				<strong>per tenant</strong>.</p>

			<div class="bs-callout bs-callout-warning">
				<h4>About Localization</h4>
				<p>It's strongly suggested to read <a href="/Pages/Documents/Localization">
		localization documentation</a> before this document.</p>
			</div>

			<h3>How To Enable?</h3>

			<div class="bs-callout bs-callout-info">
				<h4>Startup Template</h4>
				<p>If you create your project from <a href="/Templates">startup templates</a>, 
		you can skip this section since the template comes with database based 
		localization enabled by default. If you created your project before this feature, please
		read this to enable it for your application.</p>
			</div>

			<p>Database localization is designed to be backward-compatible with ASP.NET 
	Boilerplate's existing localization system. It actually replaces all 
	existing dictionary based localization sources with the <strong>
	MultiTenantLocalizationSource</strong>.</p>
			<p>MultiTenantLocalizationSource wraps existing <strong>
	DictionaryBasedLocalizationSource</strong> based sources. So, we generally wrap
				<a href="/Pages/Documents/Localization#DocLocalizeXml">XML based 
	localization</a> sources. It can not wrap <strong>Resource File</strong> sources since 
	resource files are designed to work hard-coded and static files which is not 
	proper for dynamic localization.</p>
			<p>Since it's a wrapper, underlying XML files are used as fallback source if 
	a text is not localized in the database. It may seems complicated, but easy to implement for your application. 
	Let's see how to enable database based localization.</p>
			<h4>EnableDbLocalization</h4>
			<p>First, we are enabling it:</p>
			<pre lang="cs">Configuration.Modules.Zero().LanguageManagement.EnableDbLocalization();</pre>
			<p>This should be done in the <strong>top level</strong> module's <strong>
					<a href="/Pages/Documents/Module-System#DocModulePreInit">PreInitialize</a>
				</strong> 
	method (it's the web module for a web application. Import 
	Abp.Zero.Configuration namespace (using Abp.Zero.Configuration) to see the 
	Zero() extension method).</p>
			<p>Actually, this configuration makes all the magic. But, we should make a 
	bit more to make it properly work.</p>
			<h4>Seed Database Languages</h4>
			<p>Since ABP will get list of languages from database anymore, we should 
				<strong>insert</strong> default languages to database. If you're using EntityFramework, you can 
	use seed code as
				<a href="https://github.com/aspnetboilerplate/module-zero-template/blob/master/src/AbpCompanyName.AbpProjectName.EntityFramework/Migrations/SeedData/DefaultLanguagesCreator.cs">
	like this one</a>: </p>
			<h4>Remove Static Language Configuration</h4>
			<p>If you have static language configuration as shown below, you can <strong>delete</strong> 
	these lines from your configuration code, since it will get languages from 
	database anymore.</p>
			<pre lang="cs">Configuration.Localization.Languages.Add(new LanguageInfo("en", "English", "famfamfam-flag-england", true));</pre>
			<h4>Note On Existing XML Localization Sources</h4>
			<p>
				<strong>Do not </strong>delete your XML localization files and source 
	configuration code. Because, these files are used as <strong>fallback source</strong> 
	and also all localization keys are obtained from this source.</p>
			<p>So, when you need to a new localized text, <strong>define it</strong> 
	into XML files as you do normally. You should at least define it in <strong>
	default</strong> language's XML file. Also thus, you don't need to add 
	default values of localized texts to database migration code.</p>
			<h3>Managing Languages</h3>
			<p>
				<strong>IApplicationLanguageManager</strong> interface is
				<a href="/Pages/Documents/Dependency-Injection">injected</a> and used to 
	manage languages. It has methods like GetLanguagesAsync, AddAsync, 
	RemoveAsync, UpdateAsync... to manage languages for host and tenants.</p>
			<h4>Language List Logic</h4>
			<p>List of languages are stored per tenant and for the host, and calculated as below:</p>
			<ul>
				<li>There is a list of languages for defined for <strong>the host</strong>. 
		This list is considered as <strong>default</strong> for all tenants.</li>
				<li>There is a seperated list of languages for <strong>each tenant</strong>. 
		This list <strong>inherits </strong>the host list <strong>adds </strong>
		tenant-specific languages. Tenants can not delete or update host-defined 
		(default) languages (but can override localization texts as we will see 
		later).</li>
			</ul>
			<h4>ApplicationLanguage Entity</h4>
			<p>ApplicationLanguage entity represents a language for a tenant or the 
	host.</p>
			<pre lang="cs">[Serializable]
[Table(&quot;AbpLanguages&quot;)]
public class ApplicationLanguage : <strong>FullAuditedEntity</strong>, <strong>IMayHaveTenant</strong>
{
    //...
}</pre>
			<p>It's basic properties are:</p>
			<ul>
				<li>
					<strong>TenantId</strong> (nullable): Contains the related tenant's 
		Id if this language is tenant-specific. It's null if this is a host 
		language.</li>
				<li>
					<strong>Name</strong>: Name of the language. This <strong>must be a 
		culture code</strong> from the list
					<a href="https://msdn.microsoft.com/en-us/library/ee825488(v=cs.20).aspx" target="_blank">
		here</a>.</li>
				<li>
					<strong>DisplayName</strong>: Shown name of the language. This can 
		be an arbitrary name, generally is
					<a href="https://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo.displayname(v=vs.110).aspx" target="_blank">
		CultureInfo.DisplayName</a>.</li>
				<li>
					<strong>Icon</strong>: An arbitrary icon/flag for the language. This 
		can be used to show flag of the language on UI.</li>
			</ul>
			<p>Also, ApplicationLanguage inherits <strong>FullAuditedEntity</strong> as 
	you see. That means, it's a <strong>soft-delete</strong> entity and 
	automatically <strong>audited</strong> (see
				<a href="/Pages/Documents/Entities">entity document</a> for more).</p>
			<p>ApplicationLanguage entities are stored in <strong>AbpLanguages</strong> 
	table in the database.</p>
			<h3>Managing Localization Texts</h3>
			<p>
				<strong>IApplicationLanguageTextManager</strong> interface is
				<a href="/Pages/Documents/Dependency-Injection">injected</a> and used to 
	manage localization texts. It has needed methods to get/set a localization 
	text for a tenant or the host.</p>
			<h4>Localizing A Text</h4>
			<p>Let's see what happens when you want to localize a text;</p>
			<ul>
				<li>Try to get for the <strong>current culture</strong> (got using 
		CurrentThread.CurrentUICulture).<ul>
						<li>It checks if given text is defined (overrided) for <strong>
			current tenant</strong> (got using
							<a href="/Pages/Documents/Abp-Session">IAbpSession.TenantId</a>) in
							<strong>current culture</strong> in the database. Returns the value 
			if defined.</li>
						<li>It then checks if given text is defined (overrided) for the
							<strong>host</strong> in <strong>current culture </strong>in the 
			database. Returns the value if defined.</li>
						<li>It then checks if given text is defined in the underlying XML 
			file in <strong>current culture</strong>. Returns the value if 
			defined.</li>
					</ul>
				</li>
				<li>Try to find for the <strong>fallback culture</strong>. It's 
		calculated like that: If current culture is "en-GB" then fallback 
		culture is "en".<ul>
						<li>It checks if given text is defined (overrided) for <strong>
			current tenant</strong> in <strong>fallback culture</strong> in the 
			database. Returns the value if defined.</li>
						<li>It then checks if given text is defined (overrided) for the
							<strong>host</strong> in <strong>fallback culture </strong>in the 
			database. Returns the value if defined.</li>
						<li>It then checks if given text is defined in the underlying XML 
			file in <strong>fallback culture</strong>. Returns the value if 
			defined.</li>
					</ul>
				</li>
				<li>Try to find for the <strong>default culture</strong>.<ul>
						<li>It checks if given text is defined (overrided) for <strong>
			current tenant</strong> in <strong>default culture</strong> in the 
			database. Returns the value if defined.</li>
						<li>It then checks if given text is defined (overrided) for the
							<strong>host</strong> in <strong>default culture </strong>in the 
			database. Returns the value if defined.</li>
						<li>It then checks if given text is defined in the underlying XML 
			file in <strong>default culture</strong>. Returns the value if 
			defined.</li>
					</ul>
				</li>
				<li>Get the same text or throw exception<ul>
						<li>If given text (key) is not found at all, ABP throws exception or 
			returns the same text (key) by wrapping with [ and ] (it can be 
			configured on startup, see <a href="/Pages/Documents/Localization">
			localization document</a>).</li>
					</ul>
				</li>
			</ul>

			<p>So, getting a localized text is a bit complicated. But it works fast since it 
	uses <a href="/Pages/Documents/Caching">cache</a>.</p>

			<h4>ApplicationLanguageText Entity</h4>
			<p>ApplicationLanguageText is used to store localized values in the 
	database.</p>
			<pre lang="cs">[Serializable]
[Table(&quot;AbpLanguageTexts&quot;)]
public class ApplicationLanguageText : AuditedEntity&lt;long&gt;, IMayHaveTenant
{
    //...
}</pre>
			<p>It's basic properties are;</p>
			<ul>
				<li>
					<strong>TenantId</strong> (nullable): Contains the related tenant's 
		Id if this localized text is tenant-specific. It's null if this is a host-localized 
		text.</li>
				<li>
					<strong>LanguageName</strong>: Name of the language. This <strong>must be a 
		culture code</strong> from the list
					<a href="https://msdn.microsoft.com/en-us/library/ee825488(v=cs.20).aspx" target="_blank">
		here</a>. This matches to ApplicationLanguage.Name but not forced a 
		foreign key to make it independent from the language entry.&nbsp; IApplicationLanguageTextManager 
		handles it properly.</li>
				<li>
					<strong>Source</strong>: Localization source name.</li>
				<li>
					<strong>Key</strong>: Localization text's key/name.</li>
				<li>
					<strong>Value</strong>: Localized value.</li>
			</ul>
			<p>ApplicationLanguageText entities are stored in <strong>AbpLanguageTexts</strong> 
	table in the database.</p>

		</div>

	</body>

</html>
